+Wed Jan 7 01:27:23 2004 Matthias Clasen <maclas@gmx.de>
+
+ * gdk-pixbuf/tmpl/module_interface.sgml: Document expected
+ module behaviour if the size_func returns 0.
+
+Wed Jan 7 01:26:07 2004 Matthias Clasen <maclas@gmx.de>
+
+ * gdk-pixbuf/gdk-pixbuf-sections.txt: Add gdk_pixbuf_get_file_info.
+
Mon Dec 29 01:40:20 2003 Matthias Clasen <maclas@gmx.de>
* gtk/gtk-sections.txt: Add gtk_accel_map_{un,}lock_path.
<FILE>file-loading</FILE>
gdk_pixbuf_new_from_file
gdk_pixbuf_new_from_file_at_size
+gdk_pixbuf_get_file_info
</SECTION>
<SECTION>
either ignore the size request, or only approximate it -- &gdk-pixbuf; will
then perform the required scaling on the completely loaded image.
</para>
+<para>
+If the function sets @width or @height to zero, the module should interpret
+this as a hint that it will be closed soon and shouldn't allocate further
+resources. This convention is used to implement gdk_pixbuf_get_file_info()
+efficiently.
+</para>
@width: pointer to a location containing the current image width
@height: pointer to a location containing the current image height
+Wed Jan 7 01:17:36 2004 Matthias Clasen <maclas@gmx.de>
+
+ * gdk-pixbuf-loader.c (gdk_pixbuf_loader_size_func):
+ * gdk-pixbuf-loader.c (gdk_pixbuf_loader_set_size):
+ * gdk-pixbuf-loader.c (gdk_pixbuf_loader_init): Make it possible
+ to call gdk_pixbuf_loader_set_size (loader, 0, 0) by changing
+ the initial values of priv->width/height to -1.
+
+ * io-tiff.c (tiff_image_parse):
+ * io-ras.c (RAS2State):
+ * io-pnm.c (gdk_pixbuf__pnm_image_load_increment):
+ * io-pcx.c (gdk_pixbuf__pcx_load_increment):
+ * io-jpeg.c (gdk_pixbuf__jpeg_image_load_increment):
+ * io-png.c (png_info_callback):
+ * io-ico.c (DecodeHeader):
+ * io-bmp.c (DecodeHeader): Call size_func once the size is known,
+ even if the module can't make use of the scaling information. If
+ size_func returns 0, don't allocate a pixbuf and return, if
+ necessary with an error.
+
+ * gdk-pixbuf.h:
+ * gdk-pixbuf-io.c (gdk_pixbuf_get_file_info): A new function
+ to determine the type and size of an image file without loading
+ it completely. (#53725)
+
Sun Jan 4 00:44:57 2004 Matthias Clasen <maclas@gmx.de>
* gdk-pixbuf.c (gdk_pixbuf_class_init): Turn the pixbuf
return pixbuf;
}
+static void
+info_cb (GdkPixbufLoader *loader,
+ int width,
+ int height,
+ gpointer data)
+{
+ struct {
+ GdkPixbufFormat *format;
+ int width;
+ int height;
+ } *info = data;
+
+ g_return_if_fail (width > 0 && height > 0);
+
+ info->format = gdk_pixbuf_loader_get_format (loader);
+ info->width = width;
+ info->height = height;
+
+ gdk_pixbuf_loader_set_size (loader, 0, 0);
+}
+
+/**
+ * gdk_pixbuf_get_file_info:
+ * @filename: The name of the file to identify.
+ * @width: Return location for the width of the image, or %NULL
+ * @height: Return location for the height of the image, or %NULL
+ *
+ * Parses an image file far enough to determine its format and size.
+ *
+ * Returns: A #GdkPixbufFormat describing the image format of the file
+ * or %NULL if the image format wasn't recognized. The return value
+ * is owned by GdkPixbuf and should not be freed.
+ *
+ * Since: 2.4
+ **/
+GdkPixbufFormat *
+gdk_pixbuf_get_file_info (const gchar *filename,
+ gint *width,
+ gint *height)
+{
+ GdkPixbufLoader *loader;
+ GError *temp = NULL;
+ guchar buffer [4096];
+ int length;
+ FILE *f;
+ struct {
+ GdkPixbufFormat *format;
+ gint width;
+ gint height;
+ } info;
+
+ g_return_val_if_fail (filename != NULL, NULL);
+
+ f = fopen (filename, "rb");
+ if (!f)
+ return NULL;
+
+ loader = gdk_pixbuf_loader_new ();
+
+ info.format = NULL;
+ info.width = -1;
+ info.height = -1;
+
+ g_signal_connect (loader, "size-prepared", G_CALLBACK (info_cb), &info);
+
+ while (!feof (f)) {
+ length = fread (buffer, 1, sizeof (buffer), f);
+ if (length > 0) {
+ if (!gdk_pixbuf_loader_write (loader, buffer, length, NULL))
+ break;
+ }
+ if (info.format != NULL)
+ break;
+ }
+
+ fclose (f);
+ gdk_pixbuf_loader_close (loader, NULL);
+ g_object_unref (G_OBJECT (loader));
+
+ if (width)
+ *width = info.width;
+ if (height)
+ *height = info.height;
+
+ return info.format;
+}
+
/**
* gdk_pixbuf_new_from_xpm_data:
* @data: Pointer to inline XPM data.
GdkPixbufLoaderPrivate *priv;
priv = g_new0 (GdkPixbufLoaderPrivate, 1);
+ priv->width = -1;
+ priv->height = -1;
+
loader->priv = priv;
}
gint height)
{
GdkPixbufLoaderPrivate *priv = GDK_PIXBUF_LOADER (loader)->priv;
- g_return_if_fail (width > 0 && height > 0);
+ g_return_if_fail (width >= 0 && height >= 0);
if (!priv->size_fixed)
{
GdkPixbufLoaderPrivate *priv = GDK_PIXBUF_LOADER (loader)->priv;
/* allow calling gdk_pixbuf_loader_set_size() before the signal */
- if (priv->width == 0 && priv->height == 0)
+ if (priv->width == -1 && priv->height == -1)
{
priv->width = *width;
priv->height = *height;
gchar **gdk_pixbuf_format_get_extensions (GdkPixbufFormat *format);
gboolean gdk_pixbuf_format_is_writable (GdkPixbufFormat *format);
+GdkPixbufFormat *gdk_pixbuf_get_file_info (const gchar *filename,
+ gint *width,
+ gint *height);
+
G_END_DECLS
#include <gdk-pixbuf/gdk-pixbuf-loader.h>
/* Progressive loading */
struct bmp_progressive_state {
+ GdkPixbufModuleSizeFunc size_func;
GdkPixbufModulePreparedFunc prepared_func;
GdkPixbufModuleUpdatedFunc updated_func;
gpointer user_data;
State->LineWidth = (State->LineWidth / 4) * 4 + 4;
if (State->pixbuf == NULL) {
+ if (State->size_func) {
+ gint width = State->Header.width;
+ gint height = State->Header.height;
+
+ (*State->size_func) (&width, &height, State->user_data);
+ if (width == 0 || height == 0) {
+ State->read_state = READ_STATE_DONE;
+ State->BufferSize = 0;
+ return TRUE;
+ }
+ }
+
if (State->Type == 32 ||
State->Compressed == BI_RLE4 ||
State->Compressed == BI_RLE8)
State->pixbuf =
- gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
- (gint) State->Header.width,
- (gint) State->Header.height);
+ gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
+ (gint) State->Header.width,
+ (gint) State->Header.height);
else
State->pixbuf =
- gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
- (gint) State->Header.width,
- (gint) State->Header.height);
-
- if (State->pixbuf == NULL) {
- g_set_error (error,
- GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
- _("Not enough memory to load bitmap image"));
+ gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
+ (gint) State->Header.width,
+ (gint) State->Header.height);
+
+ if (State->pixbuf == NULL) {
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+ _("Not enough memory to load bitmap image"));
State->read_state = READ_STATE_ERROR;
- return FALSE;
- }
-
+ return FALSE;
+ }
+
if (State->prepared_func != NULL)
/* Notify the client that we are ready to go */
(*State->prepared_func) (State->pixbuf, NULL, State->user_data);
-
+
+ /* make all pixels initially transparent */
+ if (State->Compressed == BI_RLE4 || State->Compressed == BI_RLE8) {
+ memset (State->pixbuf->pixels, 0, State->pixbuf->rowstride * State->Header.height);
+ State->compr.p = State->pixbuf->pixels
+ + State->pixbuf->rowstride * (State->Header.height- 1);
+ }
}
- /* make all pixels initially transparent */
- if (State->Compressed == BI_RLE4 || State->Compressed == BI_RLE8) {
- memset (State->pixbuf->pixels, 0, State->pixbuf->rowstride * State->Header.height);
- State->compr.p = State->pixbuf->pixels
- + State->pixbuf->rowstride * (State->Header.height- 1);
- }
-
State->BufferDone = 0;
if (State->Type <= 8) {
State->read_state = READ_STATE_PALETTE;
struct bmp_progressive_state *context;
context = g_new0(struct bmp_progressive_state, 1);
+ context->size_func = size_func;
context->prepared_func = prepared_func;
context->updated_func = updated_func;
context->user_data = user_data;
return FALSE;
break;
+ case READ_STATE_DONE:
+ return TRUE;
+ break;
default:
g_assert_not_reached ();
};
struct ico_progressive_state {
+ GdkPixbufModuleSizeFunc size_func;
GdkPixbufModulePreparedFunc prepared_func;
GdkPixbufModuleUpdatedFunc updated_func;
gpointer user_data;
if (State->pixbuf == NULL) {
+#if 1
+ if (State->size_func) {
+ gint width = State->Header.width;
+ gint height = State->Header.height;
+
+ (*State->size_func) (&width, &height, State->user_data);
+ if (width == 0 || height == 0) {
+ State->LineWidth = 0;
+ return;
+ }
+ }
+#endif
+
State->pixbuf =
gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
State->Header.width,
struct ico_progressive_state *context;
context = g_new0(struct ico_progressive_state, 1);
+ context->size_func = size_func;
context->prepared_func = prepared_func;
context->updated_func = updated_func;
context->user_data = user_data;
GError *decode_err = NULL;
DecodeHeader(context->HeaderBuf,
context->HeaderDone, context, &decode_err);
+ if (context->LineBuf != NULL && context->LineWidth == 0)
+ return TRUE;
+
if (decode_err) {
g_propagate_error (error, decode_err);
return FALSE;
width = cinfo->image_width;
height = cinfo->image_height;
- (* context->size_func) (&width, &height, context->user_data);
+ if (context->size_func) {
+ (* context->size_func) (&width, &height, context->user_data);
+ if (width == 0 || height == 0)
+ return FALSE;
+ }
+
for (cinfo->scale_denom = 2; cinfo->scale_denom <= 8; cinfo->scale_denom *= 2) {
jpeg_calc_output_dimensions (cinfo);
if (cinfo->output_width < width || cinfo->output_height < height) {
g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Image has invalid width and/or height"));
return FALSE;
}
- if(context->size_func)
- context->size_func(&width, &height, context->user_data);
+ if (context->size_func)
+ {
+ (*context->size_func) (&width, &height, context->user_data);
+ if (width == 0 || height == 0)
+ return TRUE;
+ }
switch(context->bpp) {
default:
png_structp png_read_ptr;
png_infop png_info_ptr;
+ GdkPixbufModuleSizeFunc size_func;
GdkPixbufModulePreparedFunc prepare_func;
GdkPixbufModuleUpdatedFunc update_func;
gpointer notify_user_data;
lc->fatal_error_occurred = FALSE;
+ lc->size_func = size_func;
lc->prepare_func = prepare_func;
lc->update_func = update_func;
lc->notify_user_data = user_data;
if (color_type & PNG_COLOR_MASK_ALPHA)
have_alpha = TRUE;
- lc->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, have_alpha, 8, width, height);
+ if (lc->size_func) {
+ gint w = width;
+ gint h = height;
+ (* lc->size_func) (&w, &h, lc->notify_user_data);
+
+ if (w == 0 || h == 0) {
+ lc->fatal_error_occurred = TRUE;
+ return;
+ }
+ }
+
+ lc->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, have_alpha, 8, width, height);
if (lc->pixbuf == NULL) {
/* Failed to allocate memory */
typedef struct {
GdkPixbufModuleUpdatedFunc updated_func;
GdkPixbufModulePreparedFunc prepared_func;
+ GdkPixbufModuleSizeFunc size_func;
gpointer user_data;
GdkPixbuf *pixbuf;
return NULL;
}
memset (context, 0, sizeof (PnmLoaderContext));
+ context->size_func = size_func;
context->prepared_func = prepared_func;
context->updated_func = updated_func;
context->user_data = user_data;
context->got_header = TRUE;
}
+
+ if (context->size_func) {
+ gint w = context->width;
+ gint h = context->height;
+ (*context->size_func) (&w, &h, context->user_data);
+
+ if (w == 0 || h == 0)
+ return FALSE;
+ }
+
/* scan until we hit image data */
if (!context->did_prescan) {
/* Progressive loading */
struct ras_progressive_state {
+ GdkPixbufModuleSizeFunc size_func;
GdkPixbufModulePreparedFunc prepared_func;
GdkPixbufModuleUpdatedFunc updated_func;
gpointer user_data;
if (!State->pixbuf) {
+ if (State->size_func) {
+ gint width = State->Header.width;
+ gint height = State->Header.height;
+
+ (*State->size_func) (&width, &height, State->user_data);
+ if (width == 0 || height == 0)
+ return FALSE;
+ }
+
if (State->RasType == 32)
State->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
(gint) State->Header.width,
struct ras_progressive_state *context;
context = g_new0(struct ras_progressive_state, 1);
+ context->size_func = size_func;
context->prepared_func = prepared_func;
context->updated_func = updated_func;
context->user_data = user_data;
gboolean prepared;
gboolean done;
+ GdkPixbufModuleSizeFunc sfunc;
GdkPixbufModulePreparedFunc pfunc;
GdkPixbufModuleUpdatedFunc ufunc;
gpointer udata;
w = LE16(ctx->hdr->width);
h = LE16(ctx->hdr->height);
+ if (ctx->sfunc) {
+ gint wi = w;
+ gint hi = h;
+
+ (*ctx->sfunc) (&wi, &hi, ctx->udata);
+
+ if (wi == 0 || hi == 0)
+ return FALSE;
+ }
+
ctx->pbuf = get_contiguous_pixbuf (w, h, alpha);
if (!ctx->pbuf) {
ctx->prepared = FALSE;
ctx->done = FALSE;
+ ctx->sfunc = f0;
ctx->pfunc = f1;
ctx->ufunc = f2;
ctx->udata = udata;
typedef struct _TiffContext TiffContext;
struct _TiffContext
{
+ GdkPixbufModuleSizeFunc size_func;
GdkPixbufModulePreparedFunc prepare_func;
GdkPixbufModuleUpdatedFunc update_func;
gpointer user_data;
return NULL;
}
+ if (context && context->size_func) {
+ gint w = width;
+ gint h = height;
+ (* context->size_func) (&w, &h, context->user_data);
+
+ if (w == 0 || h == 0)
+ return NULL;
+ }
+
pixels = g_try_malloc (bytes);
if (!pixels) {
TiffContext *context;
context = g_new0 (TiffContext, 1);
+ context->size_func = size_func;
context->prepare_func = prepare_func;
context->update_func = update_func;
context->user_data = user_data;